package jam.model;

import jam.sql.*;

import java.util.*;
import java.sql.*;

public class User {
	private int id;
	private String firstName;
	private String lastName;
	private String email;
	private String password;
	private String avatar;
	private String displayName;
	private HashSet<String> userContacts;
	private HashSet<String> channelContacts;
	private String[] sqlVars = { "id", "firstName", "lastName", "email",
			"password", "avatar", "displayName", "userContacts",
			"channelContacts" };

	public User(String firstName, String lastName, String email,
			String password, String avatar, String displayName,
			HashSet<String> userContacts, HashSet<String> channelContacts) {
		this.firstName = firstName;
		this.lastName = lastName;
		this.email = email.toLowerCase();
		this.password = password;
		this.avatar = avatar;
		this.displayName = displayName;
		this.userContacts = userContacts;
		this.channelContacts = channelContacts;
	}

	public User(String email, String password) {
		this("", "", email, password, "", "", null, null);
	}

	public User() {
		this("", "", "", "", "", "", null, null);
	}

	/**
	 * populate()
	 * 
	 * @param populateFields
	 *            HashMap mapping field names to values, to retrieve user's
	 *            information
	 * 
	 * @return true if the user's data has been successfully retrieved, false
	 *         otherwise.
	 */

	@SuppressWarnings("unchecked")
	public boolean populate(Map<String, String> populateFields) {
		SQLController sqlController = SQLController.getInstance();
		ResultSet results = null;
		try {
			results = sqlController.get("users", populateFields, sqlVars);
			if (results.next() && results.isLast()) {
				id = results.getInt("id");
				firstName = results.getString("firstName");
				lastName = results.getString("lastName");
				email = results.getString("email").toLowerCase();
				password = results.getString("password");
				avatar = results.getString("avatar");
				displayName = results.getString("displayName");
				userContacts = new HashSet<String>();
				String ucStr = results.getString("userContacts");
				if (ucStr != null && ucStr.equals("") == false) {
					for (String contactId : results.getString("userContacts")
							.split(","))
						userContacts.add(contactId);
                                }
				channelContacts = new HashSet<String>();
				String ccStr = results.getString("channelContacts");
				if (ccStr != "" && ccStr != null)
					for (String channelName : results.getString(
							"channelContacts").split(","))
						channelContacts.add(channelName);
				results.close();
				return true;
			}
		} catch (SQLException e) {
			return false;
		}
		return false;
	}

	/**
	 * Checks for the existence of a given user, based on fields given.
	 * 
	 * @param fields
	 *            HashMap mapping fields to values, to query the database with.
	 * 
	 * @return true if user exists based on fields given, false otherwise
	 */

	public static boolean exists(Map<String, String> fields) {
		SQLController sqlController = SQLController.getInstance();
		ResultSet results = null;
		try {
			results = sqlController.get("users", fields, null);
			if (results.next())
				return true;
		} catch (SQLException e) {
			System.exit(1);
		}
		return false;
	}

        public boolean passwordMatches(String password) {
            return this.password.equals(password);
        }
                
	/**
	 * Saves current user fields to the database - should be called after any
	 * changes are made to the user.
	 * 
	 * @return true if save has been successful, false otherwise.
	 */
	public boolean save() {
		SQLController sqlController = SQLController.getInstance();
		HashMap<String, String> saveFields = new HashMap<String, String>();
		saveFields.put("firstName", firstName);
		saveFields.put("lastName", lastName);
		saveFields.put("email", email);
		saveFields.put("password", password);
		saveFields.put("avatar", avatar);
		saveFields.put("displayName", displayName);
		if(userContacts != null)
			saveFields.put("userContacts", (userContacts.toString().substring(1,
				userContacts.toString().length() - 1)).replace(" ", ""));
		if(channelContacts != null)
			saveFields.put("channelContacts", (channelContacts.toString()
				.substring(1, channelContacts.toString().length() - 1))
				.replace(" ", ""));
		try {
			if (id == 0) {
				sqlController.insert("users", saveFields);
				this.populate(saveFields);
			} else {
				sqlController.update("users", id, saveFields);
			}
		} catch (SQLException e) {
			System.out.println(e);
			return false;
		}
		return true;
	}

	public static LinkedList<String> getUserInfo(String email) {
		SQLController sqlController = null;
		try {
			sqlController = SQLController.getInstance();
			HashMap<String,String> searchField = new HashMap<String,String>();
			searchField.put("email",email);
			String[] returnField = {"firstName","lastName","email","avatar","displayName"};
			ResultSet res = sqlController.get("users",searchField,returnField);
			if(res.next() && res.isLast()) {
				LinkedList<String> userInfo = new LinkedList<String>();
				userInfo.add(res.getString("firstName"));
				userInfo.add(res.getString("lastName"));
				userInfo.add(res.getString("email"));
				userInfo.add(res.getString("avatar"));
				userInfo.add(res.getString("displayName"));
				return userInfo;
			}
		} catch (SQLException e) {
			System.out.println(e);
			return null;
		}
		return null;
	}

	public LinkedList<String> getUserContacts() {
		LinkedList<String> contacts = new LinkedList<String>();
		contacts.addAll(userContacts);
		return contacts;
	}

	public LinkedList<String> getChannelContacts() {
		LinkedList<String> contacts = new LinkedList<String>();
		contacts.addAll(channelContacts);
		return contacts;
	}

	/*public boolean addUserContact(int userid) {
		HashMap<String, String> checkFields = new HashMap<String,String>();
		checkFields.put("id","" + userid);
		if(User.exists(checkFields) && userid != id) {
			userContacts.add(userid);
			return this.save();
		}
		return false;
	}*/

	public boolean addUserContact(String username) {
		userContacts.add(username);
		return this.save();
	}

	public boolean addChannelContact(String channelName) {
		channelContacts.add(channelName);
		return this.save();
	}

	public boolean deleteUserContact(String username) {
		userContacts.remove(username);
		return this.save();
	}

	public boolean deleteChannelContact(String channelName) {
		if(!channelContacts.contains(channelName)) return false;
		channelContacts.remove(channelName);
		return this.save();
	}
     
	/**
	 * getUsername()
	 * 
	 * @return lowercase string representation of this user's username (e-mail
	 *         address)
	 */

	public String getUsername() {
		return this.email.toLowerCase();
	}

	public String toString() {
		return id + ": " + firstName + " " + lastName;
	}

	// getters
        
	public String getFirstName() {
		return firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public String getEmail() {
		return email;
	}

	public String getPassword() {
		return password;
	}

	public String getDisplayName() {
		return displayName;
	}

	public String getAvatar() {
		return avatar;
	}

	// setters

	public void setFirstName(String firstName) {
		this.firstName = firstName;
		this.save();
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
		this.save();
	}

	public void setEmail(String email) {
		this.email = email.toLowerCase();
		this.save();
	}

	public void setPassword(String password) {
		this.password = password;
		this.save();
	}

	public void setDisplayName(String displayName) {
		this.displayName = displayName;
		this.save();
	}

	public void setAvatar(String avatar) {
		this.avatar = avatar;
		this.save();
	}

}
